﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;

using Skyhook.Core.Graphics;

namespace Skyhook.Core.Helpers
{
    public static class IsoUtils
    {
        public const float LandscapeTileWidth = 512.0f;
        public const float LandscapeTileHeight = 256.0f;

        public const float WorldTileWidth = 64.0f;
        public const float WorldTileHeight = 32.0f;

        const float IsoZAxisRotation = 45.0f * 2 * (float)Math.PI / 360.0f;

        static Matrix LandscapeToScreen;
        static Matrix ScreenToLandscape;

        static Matrix WorldToScreen;
        static Matrix ScreenToWorld;

        static Matrix OrthohraphicProjection;

        private static void SetupLandscapeMatrix()
        {
            LandscapeToScreen = new Matrix();
            LandscapeToScreen = Matrix.CreateRotationZ(IsoZAxisRotation);
            LandscapeToScreen *= Matrix.CreateScale(1, (float)(LandscapeTileHeight / Math.Sqrt(2.0)), 1);
            LandscapeToScreen *= Matrix.CreateScale((float)(LandscapeTileWidth / Math.Sqrt(2.0)), 1, 1);

            ScreenToLandscape = new Matrix();
            ScreenToLandscape = Matrix.CreateScale(1.0f / (float)(LandscapeTileWidth / Math.Sqrt(2.0)), 1, 1);
            ScreenToLandscape *= Matrix.CreateScale(1, 1.0f / (float)(LandscapeTileHeight / Math.Sqrt(2.0)), 1);
            ScreenToLandscape *= Matrix.CreateRotationZ(-IsoZAxisRotation);          
        }

        private static void SetupWorldMatrix()
        {
            WorldToScreen = new Matrix();
            WorldToScreen = Matrix.CreateRotationZ(IsoZAxisRotation);
            WorldToScreen *= Matrix.CreateScale(1, (float)(WorldTileHeight / Math.Sqrt(2.0)), 1);
            WorldToScreen *= Matrix.CreateScale((float)(WorldTileWidth / Math.Sqrt(2.0)), 1, 1);

            ScreenToWorld = new Matrix();
            ScreenToWorld = Matrix.CreateScale(1.0f / (float)(WorldTileWidth / Math.Sqrt(2.0)), 1, 1);
            ScreenToWorld *= Matrix.CreateScale(1, 1.0f / (float)(WorldTileHeight / Math.Sqrt(2.0)), 1);
            ScreenToWorld *= Matrix.CreateRotationZ(-IsoZAxisRotation);
        }

        private static void SetupProjectionMatrix()
        {
            OrthohraphicProjection = Matrix.CreateTranslation(-0.5f, -0.5f, 0);
            OrthohraphicProjection *= Matrix.CreateOrthographicOffCenter(0, GraphicsManager.ViewportWidth, GraphicsManager.ViewportHeight, 0, 0, 1);
        }

        static IsoUtils()
        {
            SetupProjectionMatrix();
            SetupLandscapeMatrix();
            SetupWorldMatrix();
        }

        public static Matrix LandscapeToScreenMatrix
        {
            get
            {
                return LandscapeToScreen;
            }
        }

        public static Matrix ScreenToLandscapeMatrix
        {
            get
            {
                return ScreenToLandscape;
            }
        }

        public static Vector2 ConvertScreenToLandscape(int x, int y)
        {
            Vector2 result = new Vector2();
            Vector4 landcoords = new Vector4(x,y,0,1);
            landcoords = Vector4.Transform(landcoords, ScreenToLandscape);
            result.X = landcoords.X;
            result.Y = landcoords.Y;
            return result;
        }

        public static Vector2 ConvertScreenToLandscapeTiles(int x, int y)
        {
            Vector2 landpos = ConvertScreenToLandscape(x, y);
            Vector2 result = new Vector2();

            result.X = (int)landpos.X;
            result.Y = (int)landpos.Y;

            if (landpos.X < 0)
            {
                result.X = result.X - 1;
            }
            if (landpos.Y < 0)
            {
                result.Y = result.Y - 1;
            }
            return result;
        }

        public static Vector2 ConvertLandscapeToScreen(float x, float y)
        {
            Vector2 result = new Vector2();
            Vector4 landcoords = new Vector4(x, y, 0, 1);
            landcoords = Vector4.Transform(landcoords, LandscapeToScreen);
            result.X = landcoords.X;
            result.Y = landcoords.Y;
            return result;
        }

        public static Matrix WorldToScreenMatrix
        {
            get
            {
                return WorldToScreen;
            }
        }

        public static Matrix ScreenToWorldMatrix
        {
            get
            {
                return ScreenToWorld;
            }
        }

        public static Vector2 ConvertScreenToWorld(int x, int y)
        {
            Vector2 result = new Vector2();
            Vector4 landcoords = new Vector4(x, y, 0, 1);
            landcoords = Vector4.Transform(landcoords, ScreenToWorld);
            result.X = landcoords.X;
            result.Y = landcoords.Y;
            return result;
        }
        public static Vector2 ConvertScreenToWorldTiles(int x, int y)
        {
            Vector2 landpos = ConvertScreenToWorld(x, y);
            Vector2 result = new Vector2();

            result.X = (int)landpos.X;
            result.Y = (int)landpos.Y;

            if (landpos.X < 0)
            {
                result.X = result.X - 1;
            }
            if (landpos.Y < 0)
            {
                result.Y = result.Y - 1;
            }
            return result;
        }

        public static Vector2 ConvertWorldToScreen(float x, float y)
        {
            Vector2 result = new Vector2();
            Vector4 landcoords = new Vector4(x, y, 0, 1);
            landcoords = Vector4.Transform(landcoords, WorldToScreen);
            result.X = landcoords.X;
            result.Y = landcoords.Y;
            return result;
        }

        public static Matrix OrthohraphicProjectionMatrix
        {
            get
            {
                return OrthohraphicProjection;
            }
        }
    }
}
